/*
* $Id: FamilyManager.cpp 154 2010-09-27 08:10:48Z volok-aleksej@yandex.ru $
*
* Copyright 2010 by Volokitin Alexey
* All rights reserved
*
*/
#include "Common/include.h"
#include "FamilyManager.h"
#include "InspectManager.h"
#include "QueenBeeManager.h"
#include "Database/Tables/PointsTable.h"
#include "Database/Tables/FamiliesTable.h"
#include "Database/Operation/AddFamilyOperation.h"
#include "Database/Operation/AddPointOperation.h"
#include "Database/Operation/ChangeFamilyOperation.h"
#include "Database/Operation/ChangePointOperation.h"
#include "Database/Operation/RenameOperation.h"
#include "Database/Operation/DeleteOperation.h"
#include "Event/EventId.h"

#include "Common/RefObject.h"
CRefObject<CFamilyManager> g_FamilyManager;
CFamilyManager* IJournalComponent::GetFamilyManager(){
	return g_FamilyManager.GetObject();
}

/************************************************************************/
/*                     CFamilyManager::point                            */
/************************************************************************/
CFamilyManager::point::point() : m_nIdRecord(0){}
CFamilyManager::point::point(const point& pnt){
	operator = (pnt);
}
void CFamilyManager::point::operator = (const point& pnt){
	m_strName = pnt.m_strName;
	m_strNote = pnt.m_strNote;
	m_nIdRecord = pnt.m_nIdRecord;
}
/************************************************************************/
/*                     CFamilyManager::family                           */
/************************************************************************/
CFamilyManager::family::family() : m_nIdRecord(0), m_type(Family::DEFAULT){}
CFamilyManager::family::family(const family& fml){
	operator = (fml);
}
void CFamilyManager::family::operator = (const family& fml){
	m_strName = fml.m_strName;
	m_strNote = fml.m_strNote;
	m_nIdRecord = fml.m_nIdRecord;
	m_type = fml.m_type;
	m_nIdPoint = fml.m_nIdPoint;
}
/************************************************************************/
/*                          CFamilyManager                              */
/************************************************************************/
CFamilyManager::CFamilyManager(){}
CFamilyManager::~CFamilyManager(){}

void CFamilyManager::Init(){
	IDatabase* db = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CPointsTable pointsTable;
	IResult* pResult = pointsTable.GetValue(db);
	for(int i = 0; i < (int)pResult->GetSizeResult(); i++){
		point pnt;
		CPointsTable::content* pContent = (CPointsTable::content*)(*pResult)[i];
		pnt.m_strName = pContent->s_strName;
		pnt.m_strNote = pContent->s_strNote;
		pnt.m_nIdRecord = pContent->s_nIdRecord;
		m_aPoints.insert(std::make_pair(pContent->s_nId, pnt));
	}
	pResult->Free();
	CFamiliesTable familiesTable;
	pResult = familiesTable.GetValue(db);
	for(int i = 0; i < (int)pResult->GetSizeResult(); i++){
		CFamiliesTable::content* pContent = (CFamiliesTable::content*)(*pResult)[i];
		family fml;
		fml.m_strName = pContent->s_strName;
		fml.m_strNote = pContent->s_strNote;
		fml.m_type = pContent->s_type;
		fml.m_nIdRecord = pContent->s_nIdRecord;
		fml.m_nIdPoint = pContent->s_nIdPoint;
		m_aPntFamily[fml.m_nIdPoint].push_back(pContent->s_nId);
		m_aFamily.insert(std::make_pair(pContent->s_nId, fml));
	}
	pResult->Free();
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(db);
}

std::map<int, CFamilyManager::point> CFamilyManager::GetPoints(){
	return m_aPoints;
}

std::map<int, CFamilyManager::family> CFamilyManager::GetFamilies(int nIdPoint){
	std::map<int, family> aFamilies;
	for(std::vector<int>::iterator it = m_aPntFamily[nIdPoint].begin(); it != m_aPntFamily[nIdPoint].end(); it++){
		std::map<int, family>::iterator it1 = m_aFamily.find(*it);
		if(it1 != m_aFamily.end())
			aFamilies.insert(std::make_pair(*it, it1->second));
	}
	return aFamilies;
}

std::map<int, CFamilyManager::family> CFamilyManager::GetFamilies(){
	return m_aFamily;
}

CFamilyManager::family CFamilyManager::GetFamily(int nIdFamily){
	std::map<int, family>::iterator it = m_aFamily.find(nIdFamily);
	if(it != m_aFamily.end())
		return it->second;
	return family();
}

CFamilyManager::point CFamilyManager::GetPoint(int nId){
	std::map<int, point>::iterator it = m_aPoints.find(nId);
	if(it != m_aPoints.end())
		return it->second;
	return point();
}

int CFamilyManager::AddFamily(family fml, int nIdHousing, const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Add Family"));
	CAddFamilyOperation operation;
	operation.m_content.s_nIdPoint = fml.m_nIdPoint;
	operation.m_content.s_strName = fml.m_strName;
	operation.m_content.s_strNote = fml.m_strNote;
	operation.m_content.s_nType = fml.m_type;
	operation.m_content.s_nIdHousing = nIdHousing;
	operation.m_content.s_aUserFields = aUserFields;
	operation.AddValue(pDb);
	pDb->EndTransaction(_T("Add Family"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);

	fml.m_nIdRecord = operation.m_content.s_nIdRecord;
	m_aFamily.insert(std::make_pair(operation.m_content.s_nId, fml));
	m_aPntFamily[fml.m_nIdPoint].push_back(operation.m_content.s_nId);
	IEventManager::GetEventManager()->SendEvent(FAMILIES_DB_CHANGE_EVENT);
	return operation.m_content.s_nId;
}

void CFamilyManager::AddPoint(point pnt, const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Add Point"));
	CAddPointOperation operation;
	operation.m_content.s_strName = pnt.m_strName;
	operation.m_content.s_strNote = pnt.m_strNote;
	operation.m_content.s_aUserFields = aUserFields;
	operation.AddValue(pDb);
	pDb->EndTransaction(_T("Add Point"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	pnt.m_nIdRecord = operation.m_content.s_nIdRecord;
	m_aPoints.insert(std::make_pair(operation.m_content.s_nId, pnt));
	IEventManager::GetEventManager()->SendEvent(POINTS_DB_CHANGE_EVENT);
}

void CFamilyManager::ChangeFamily(int nId, family fml, const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Update Family"));
	CChangeFamilyOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_nIdPoint = fml.m_nIdPoint;
	operation.m_content.s_strName = fml.m_strName;
	operation.m_content.s_strNote = fml.m_strNote;
	operation.m_content.s_nType = fml.m_type;
	operation.m_content.s_aUserFields = aUserFields;
	operation.UpdateValue(pDb);
	fml.m_nIdRecord = operation.m_content.s_nIdRecord;
	pDb->EndTransaction(_T("Update Family"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	m_aFamily[nId] = fml;
	IEventManager::GetEventManager()->SendEvent(FAMILIES_DB_CHANGE_EVENT);
}

void CFamilyManager::ChangePoint(int nId, point pnt, const std::map<std::tstring, std::tstring>& aUserFields){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Change Point"));
	CChangePointOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_strName = pnt.m_strName;
	operation.m_content.s_strNote = pnt.m_strNote;
	operation.m_content.s_aUserFields = aUserFields;
	operation.UpdateValue(pDb);
	pnt.m_nIdRecord = operation.m_content.s_nIdRecord;
	pDb->EndTransaction(_T("Change Point"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);
	m_aPoints[nId] = pnt;
	IEventManager::GetEventManager()->SendEvent(POINTS_DB_CHANGE_EVENT);
}

void CFamilyManager::RenameFamily(int nId, const std::tstring& strNewName){
	Rename(nId, CRenameOperation::content::FAMILY, strNewName);
	m_aFamily[nId].m_strName = strNewName;
	IEventManager::GetEventManager()->SendEvent(FAMILIES_DB_CHANGE_EVENT);
}

void CFamilyManager::RenamePoint(int nId, const std::tstring& strNewName){
	Rename(nId, CRenameOperation::content::POINT, strNewName);
	m_aPoints[nId].m_strName = strNewName;
	IEventManager::GetEventManager()->SendEvent(POINTS_DB_CHANGE_EVENT);
}

void CFamilyManager::Rename(int nId, int type, const std::tstring& strNewName){
	IDatabase* pDatabase = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	CRenameOperation operation;
	operation.m_content.s_type = (CRenameOperation::content::typeRename)type;
	operation.m_content.s_nId = nId;
	operation.m_content.s_strNewName = strNewName;
	operation.UpdateValue(pDatabase);
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDatabase);
}

void CFamilyManager::DeletePoint(int nId){
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Delete Point"));
	CDeleteOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_type = CDeleteOperation::content::POINT;
	operation.DeleteValue(pDb);
	for(std::vector<int>::const_iterator it = m_aPntFamily[nId].begin(); it != m_aPntFamily[nId].end(); it++)
		DelFamily(*it, pDb);
	pDb->EndTransaction(_T("Delete Point"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);

	m_aPoints.erase(nId);
	m_aPntFamily.erase(nId);
	IEventManager::GetEventManager()->SendEvent(POINTS_DB_CHANGE_EVENT);
	IEventManager::GetEventManager()->SendEvent(FAMILIES_DB_CHANGE_EVENT);
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CFamilyManager::DeleteFamily(int nId){
	int nIdPoint = m_aFamily[nId].m_nIdPoint;
	IDatabase* pDb = IDatabaseManager::GetDatabaseManager()->OpenDatabase(JOURNAL_DATABASE_NAME);
	pDb->BeginTransaction(_T("Delete Family"));
	IJournalComponent::GetQueenBeeManager()->DeleteFamilyQB(nId);
	DelFamily(nId, pDb);
	pDb->EndTransaction(_T("Delete Family"));
	IDatabaseManager::GetDatabaseManager()->CloseDatabase(pDb);

	std::vector<int>& aIds = m_aPntFamily[nIdPoint];
	std::vector<int>::iterator it = std::find(aIds.begin(), aIds.end(), nId);
	if(it != aIds.end())
		aIds.erase(it);
	IEventManager::GetEventManager()->SendEvent(FAMILIES_DB_CHANGE_EVENT);
	IEventManager::GetEventManager()->SendEvent(JOURNAL_DB_CHANGE_EVENT);
}

void CFamilyManager::DelFamily(int nId, IDatabase* pDb){
	CDeleteOperation operation;
	operation.m_content.s_nId = nId;
	operation.m_content.s_type = CDeleteOperation::content::FAMILY;
	operation.DeleteValue(pDb);
	m_aFamily.erase(nId);
	IJournalComponent::GetInspectManager()->DeleteInspects(nId);
}

